# import cv2
# import matplotlib.pyplot as plt
#
# # 设置matplotlib支持中文显示
# plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]
#
#
# def process_license_plate(image_path):
#     try:
#         # 读取图像
#         image = cv2.imread(image_path)
#         if image is None:
#             print(f"无法读取图像: {image_path}")
#             return
#
#         # 转换为RGB以便matplotlib正确显示
#         rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
#
#         # 转换为HSV格式
#         hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
#
#         # 创建图像显示窗口
#         plt.figure(figsize=(12, 5))
#
#         # 显示原图
#         plt.subplot(121)
#         plt.imshow(rgb_image)
#         plt.title('原始图像')
#         plt.axis('off')
#
#         # 显示HSV转换后的图像
#         plt.subplot(122)
#         plt.imshow(hsv_image)
#         plt.title('HSV格式图像')
#         plt.axis('off')
#
#         # 调整布局并显示图像
#         plt.tight_layout()
#         plt.show()
#
#     except Exception as e:
#         print(f"处理图像时出错: {e}")
#
#
# if __name__ == "__main__":
#     # 指定车牌照片路径，请替换为实际路径
#     image_path = "3.png"
#     process_license_plate(image_path)


# import cv2
# import matplotlib.pyplot as plt
# import numpy as np
# import os
#
# # 设置matplotlib支持中文显示
# plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]
#
#
# def process_license_plate(image_path, interactive=False):
#     try:
#         # 检查文件是否存在
#         if not os.path.exists(image_path):
#             print(f"错误：文件不存在 - {image_path}")
#             return
#
#         # 获取文件绝对路径，便于调试
#         abs_path = os.path.abspath(image_path)
#         print(f"尝试读取文件: {abs_path}")
#
#         # 读取图像
#         image = cv2.imread(image_path)
#         if image is None:
#             print(f"无法读取图像: {image_path}")
#             print("可能原因：文件损坏、不支持的格式或权限不足")
#             return
#
#         # 转换为RGB以便matplotlib正确显示
#         rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
#
#         # 转换为HSV格式
#         hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
#
#         if interactive:
#             # 交互式阈值调试
#             lower, upper = debug_hsv_thresholds(image.copy())
#             enhanced_plate = extract_license_plate(image.copy(), hsv_image, lower, upper)
#         else:
#             # 使用默认阈值
#             enhanced_plate = extract_license_plate(image.copy(), hsv_image)
#
#         # 创建图像显示窗口
#         plt.figure(figsize=(16, 10))
#
#         # 显示原图
#         plt.subplot(221)
#         plt.imshow(rgb_image)
#         plt.title('原始图像')
#         plt.axis('off')
#
#         # 显示HSV转换后的图像
#         plt.subplot(222)
#         plt.imshow(hsv_image)
#         plt.title('HSV格式图像')
#         plt.axis('off')
#
#         # 显示提取的车牌
#         plt.subplot(223)
#         if enhanced_plate is not None:
#             plt.imshow(cv2.cvtColor(enhanced_plate, cv2.COLOR_BGR2RGB))
#             plt.title('提取的车牌')
#         else:
#             plt.text(0.5, 0.5, '未找到车牌', ha='center', va='center')
#         plt.axis('off')
#
#         # 显示标记车牌的原图
#         plt.subplot(224)
#         if enhanced_plate is not None:
#             plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
#             plt.title('标记的车牌位置')
#         else:
#             plt.imshow(rgb_image)
#             plt.title('未找到车牌')
#         plt.axis('off')
#
#         # 调整布局并显示图像
#         plt.tight_layout()
#         plt.show()
#
#     except Exception as e:
#         print(f"处理图像时出错: {e}")
#
#
# def debug_hsv_thresholds(image):
#     """交互式调试HSV阈值"""
#     # 转换为HSV
#     hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
#
#     # 创建窗口
#     cv2.namedWindow('HSV阈值调试')
#
#     # 创建滑动条
#     def nothing(x):
#         pass
#
#     # 初始阈值设置（蓝色车牌）
#     cv2.createTrackbar('HMin', 'HSV阈值调试', 100, 179, nothing)
#     cv2.createTrackbar('SMin', 'HSV阈值调试', 150, 255, nothing)
#     cv2.createTrackbar('VMin', 'HSV阈值调试', 0, 255, nothing)
#     cv2.createTrackbar('HMax', 'HSV阈值调试', 140, 179, nothing)
#     cv2.createTrackbar('SMax', 'HSV阈值调试', 255, 255, nothing)
#     cv2.createTrackbar('VMax', 'HSV阈值调试', 255, 255, nothing)
#
#     print("调整滑动条以获得最佳效果，按ESC键确认并继续...")
#
#     while True:
#         # 获取当前滑动条值
#         h_min = cv2.getTrackbarPos('HMin', 'HSV阈值调试')
#         s_min = cv2.getTrackbarPos('SMin', 'HSV阈值调试')
#         v_min = cv2.getTrackbarPos('VMin', 'HSV阈值调试')
#         h_max = cv2.getTrackbarPos('HMax', 'HSV阈值调试')
#         s_max = cv2.getTrackbarPos('SMax', 'HSV阈值调试')
#         v_max = cv2.getTrackbarPos('VMax', 'HSV阈值调试')
#
#         # 创建掩码
#         lower = np.array([h_min, s_min, v_min])
#         upper = np.array([h_max, s_max, v_max])
#         mask = cv2.inRange(hsv, lower, upper)
#         result = cv2.bitwise_and(image, image, mask=mask)
#
#         # 显示结果
#         cv2.imshow('HSV阈值调试', result)
#
#         # 按ESC键退出
#         key = cv2.waitKey(1) & 0xFF
#         if key == 27:  # ESC键
#             break
#
#     cv2.destroyAllWindows()
#     print(f"使用阈值: lower={lower}, upper={upper}")
#     return lower, upper
#
#
# def extract_license_plate(original_img, hsv_img, lower_blue=None, upper_blue=None):
#     """提取并增强车牌区域"""
#     try:
#         # 使用默认阈值或传入的阈值
#         if lower_blue is None:
#             lower_blue = np.array([100, 150, 0])
#         if upper_blue is None:
#             upper_blue = np.array([140, 255, 255])
#
#         # 创建蓝色掩码
#         blue_mask = cv2.inRange(hsv_img, lower_blue, upper_blue)
#
#         # 形态学操作：开运算和闭运算
#         kernel = np.ones((5, 5), np.uint8)
#         opening = cv2.morphologyEx(blue_mask, cv2.MORPH_OPEN, kernel, iterations=2)
#         closing = cv2.morphologyEx(opening, cv2.MORPH_CLOSE, kernel, iterations=3)
#
#         # 寻找轮廓
#         contours, _ = cv2.findContours(closing.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
#
#         # 按面积排序，保留最大的几个轮廓
#         contours = sorted(contours, key=cv2.contourArea, reverse=True)[:10]
#
#         plate_contour = None
#         plate_rect = None
#
#         # 寻找近似矩形的轮廓
#         for contour in contours:
#             perimeter = cv2.arcLength(contour, True)
#             approx = cv2.approxPolyDP(contour, 0.02 * perimeter, True)
#
#             # 车牌通常是矩形
#             if len(approx) == 4:
#                 plate_contour = approx
#                 plate_rect = cv2.boundingRect(approx)
#                 break
#
#         if plate_contour is not None:
#             # 提取车牌区域
#             x, y, w, h = plate_rect
#             aspect_ratio = w / h
#
#             # 验证车牌的宽高比（中国车牌标准约为2.5:1）
#             if 2.0 < aspect_ratio < 4.0:
#                 # 在原图上标记车牌区域
#                 cv2.drawContours(original_img, [plate_contour], -1, (0, 255, 0), 2)
#
#                 # 提取车牌区域
#                 license_plate = original_img[y:y + h, x:x + w]
#
#                 # 增强对比度
#                 gray_plate = cv2.cvtColor(license_plate, cv2.COLOR_BGR2GRAY)
#
#                 # 使用自适应直方图均衡化增强细节
#                 clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
#                 enhanced_plate = clahe.apply(gray_plate)
#
#                 # 转回彩色显示
#                 enhanced_plate = cv2.cvtColor(enhanced_plate, cv2.COLOR_GRAY2BGR)
#
#                 return enhanced_plate
#
#         return None
#
#     except Exception as e:
#         print(f"提取车牌时出错: {e}")
#         return None
#
#
# if __name__ == "__main__":
#     # 指定车牌照片路径，请替换为实际路径
#     image_path = r"1.jpg"  # 请根据实际情况修改
#
#     # 是否启用交互式阈值调试
#     interactive_mode = True  # 设置为True启用调试模式
#
#     # 打印工作目录，便于调试
#     print(f"当前工作目录: {os.getcwd()}")
#     process_license_plate(image_path, interactive_mode)


import cv2
import matplotlib.pyplot as plt
import numpy as np
import os

# 设置matplotlib支持中文显示
plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]


def process_license_plate(image_path, interactive=False):
    try:
        # 检查文件是否存在
        if not os.path.exists(image_path):
            print(f"错误：文件不存在 - {image_path}")
            return

        # 获取文件绝对路径，便于调试
        abs_path = os.path.abspath(image_path)
        print(f"尝试读取文件: {abs_path}")

        # 读取图像
        image = cv2.imread(image_path)
        if image is None:
            print(f"无法读取图像: {image_path}")
            print("可能原因：文件损坏、不支持的格式或权限不足")
            return

        # 转换为RGB以便matplotlib正确显示
        rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

        # 转换为HSV格式
        hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)

        if interactive:
            # 交互式阈值调试
            lower, upper = debug_hsv_thresholds(image.copy())
            plates_info = locate_license_plates(image.copy(), hsv_image, lower, upper)
        else:
            # 使用默认阈值
            plates_info = locate_license_plates(image.copy(), hsv_image)

        # 创建图像显示窗口
        plt.figure(figsize=(16, 10))

        # 显示原图
        plt.subplot(221)
        plt.imshow(rgb_image)
        plt.title('原始图像')
        plt.axis('off')

        # 显示HSV转换后的图像
        plt.subplot(222)
        plt.imshow(hsv_image)
        plt.title('HSV格式图像')
        plt.axis('off')

        # 显示定位结果
        plt.subplot(223)
        if plates_info:
            result_img = image.copy()
            for plate in plates_info:
                plate_contour, plate_rotated = plate
                cv2.drawContours(result_img, [plate_contour], -1, (0, 255, 0), 2)
            plt.imshow(cv2.cvtColor(result_img, cv2.COLOR_BGR2RGB))
            plt.title(f'定位到 {len(plates_info)} 个车牌')
        else:
            plt.imshow(rgb_image)
            plt.title('未找到车牌')
        plt.axis('off')

        # 显示提取的车牌
        plt.subplot(224)
        if plates_info:
            # 创建车牌拼贴
            max_plates = min(4, len(plates_info))  # 最多显示4个车牌
            plate_collage = create_plate_collage([plate[1] for plate in plates_info[:max_plates]])
            plt.imshow(cv2.cvtColor(plate_collage, cv2.COLOR_BGR2RGB))
            plt.title('提取的车牌')
        else:
            plt.text(0.5, 0.5, '未找到车牌', ha='center', va='center')
        plt.axis('off')

        # 调整布局并显示图像
        plt.tight_layout()
        plt.show()

    except Exception as e:
        print(f"处理图像时出错: {e}")


def debug_hsv_thresholds(image):
    """交互式调试HSV阈值"""
    # 转换为HSV
    hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)

    # 创建窗口
    cv2.namedWindow('HSV阈值调试')

    # 创建滑动条
    def nothing(x):
        pass

    # 初始阈值设置（蓝色车牌）
    cv2.createTrackbar('HMin', 'HSV阈值调试', 100, 179, nothing)
    cv2.createTrackbar('SMin', 'HSV阈值调试', 150, 255, nothing)
    cv2.createTrackbar('VMin', 'HSV阈值调试', 0, 255, nothing)
    cv2.createTrackbar('HMax', 'HSV阈值调试', 140, 179, nothing)
    cv2.createTrackbar('SMax', 'HSV阈值调试', 255, 255, nothing)
    cv2.createTrackbar('VMax', 'HSV阈值调试', 255, 255, nothing)

    print("调整滑动条以获得最佳效果，按ESC键确认并继续...")

    while True:
        # 获取当前滑动条值
        h_min = cv2.getTrackbarPos('HMin', 'HSV阈值调试')
        s_min = cv2.getTrackbarPos('SMin', 'HSV阈值调试')
        v_min = cv2.getTrackbarPos('VMin', 'HSV阈值调试')
        h_max = cv2.getTrackbarPos('HMax', 'HSV阈值调试')
        s_max = cv2.getTrackbarPos('SMax', 'HSV阈值调试')
        v_max = cv2.getTrackbarPos('VMax', 'HSV阈值调试')

        # 创建掩码
        lower = np.array([h_min, s_min, v_min])
        upper = np.array([h_max, s_max, v_max])
        mask = cv2.inRange(hsv, lower, upper)
        result = cv2.bitwise_and(image, image, mask=mask)

        # 显示结果
        cv2.imshow('HSV阈值调试', result)

        # 按ESC键退出
        key = cv2.waitKey(1) & 0xFF
        if key == 27:  # ESC键
            break

    cv2.destroyAllWindows()
    print(f"使用阈值: lower={lower}, upper={upper}")
    return lower, upper


def locate_license_plates(original_img, hsv_img, lower_blue=None, upper_blue=None):
    """定位并提取车牌区域，支持多车牌"""
    try:
        # 使用默认阈值或传入的阈值
        if lower_blue is None:
            lower_blue = np.array([100, 150, 0])
        if upper_blue is None:
            upper_blue = np.array([140, 255, 255])

        # 创建蓝色掩码
        blue_mask = cv2.inRange(hsv_img, lower_blue, upper_blue)

        # 形态学操作：开运算和闭运算
        kernel = np.ones((5, 5), np.uint8)
        opening = cv2.morphologyEx(blue_mask, cv2.MORPH_OPEN, kernel, iterations=2)
        closing = cv2.morphologyEx(opening, cv2.MORPH_CLOSE, kernel, iterations=3)

        # 寻找轮廓
        contours, _ = cv2.findContours(closing.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

        # 按面积排序，保留最大的几个轮廓
        contours = sorted(contours, key=cv2.contourArea, reverse=True)[:15]

        plates_info = []  # 存储车牌信息：[(轮廓, 旋转校正后的车牌), ...]

        # 寻找近似矩形的轮廓
        for contour in contours:
            # 计算轮廓面积
            area = cv2.contourArea(contour)

            # 过滤过小的区域
            if area < 2000:
                continue

            # 获取最小外接矩形
            rect = cv2.minAreaRect(contour)
            box = cv2.boxPoints(rect)
            box = np.int0(box)

            # 计算宽高比
            width, height = rect[1]
            aspect_ratio = max(width, height) / min(width, height)

            # 验证车牌的宽高比（中国车牌标准约为2.5:1）
            if 1.8 < aspect_ratio < 5.0:
                # 获取旋转矩阵
                angle = rect[2]
                (h, w) = original_img.shape[:2]
                center = (w // 2, h // 2)

                # 校正车牌角度
                M = cv2.getRotationMatrix2D(center, angle, 1.0)
                rotated = cv2.warpAffine(original_img, M, (w, h))

                # 提取校正后的车牌区域
                Xs = [i[0] for i in box]
                Ys = [i[1] for i in box]
                x1 = min(Xs)
                x2 = max(Xs)
                y1 = min(Ys)
                y2 = max(Ys)

                # 确保坐标在图像范围内
                x1 = max(0, x1)
                y1 = max(0, y1)
                x2 = min(w, x2)
                y2 = min(h, y2)

                # 提取车牌
                if x2 > x1 and y2 > y1:
                    license_plate = rotated[y1:y2, x1:x2]

                    # 增强对比度
                    gray_plate = cv2.cvtColor(license_plate, cv2.COLOR_BGR2GRAY)
                    clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
                    enhanced_plate = clahe.apply(gray_plate)
                    enhanced_plate = cv2.cvtColor(enhanced_plate, cv2.COLOR_GRAY2BGR)

                    plates_info.append((box, enhanced_plate))

        return plates_info

    except Exception as e:
        print(f"定位车牌时出错: {e}")
        return []


def create_plate_collage(plates):
    """创建车牌拼贴图像"""
    if not plates:
        return np.zeros((100, 100, 3), dtype=np.uint8)

    # 调整所有车牌图像为相同高度
    max_height = max(plate.shape[0] for plate in plates)
    resized_plates = []

    for plate in plates:
        h, w = plate.shape[:2]
        ratio = max_height / h
        new_w = int(w * ratio)
        resized = cv2.resize(plate, (new_w, max_height))
        resized_plates.append(resized)

    # 创建拼贴
    total_width = sum(plate.shape[1] for plate in resized_plates)
    collage = np.zeros((max_height, total_width, 3), dtype=np.uint8)

    x_offset = 0
    for plate in resized_plates:
        h, w = plate.shape[:2]
        collage[0:h, x_offset:x_offset + w] = plate
        x_offset += w

    return collage


if __name__ == "__main__":
    # 指定车牌照片路径，请替换为实际路径
    image_path = r"3.png"  # 请根据实际情况修改

    # 是否启用交互式阈值调试
    interactive_mode = True  # 设置为True启用调试模式

    # 打印工作目录，便于调试
    print(f"当前工作目录: {os.getcwd()}")
    process_license_plate(image_path, interactive_mode)